package models

import (
	"fmt"
	"time"
	"strings"
	"strconv"

	"github.com/astaxie/beego/orm"

	"read.com/admin/libs"
)

type Book struct {
	Id                int       `orm:"column(id);auto"`
	Status            int8      `orm:"column(status)" description:"状态"`
	Name              string    `orm:"column(name);size(20)" description:"书名"`
	Words             int       `orm:"column(words)" description:"字数"`
	Category          int       `orm:"column(category)" description:"分类"`
	Tags              string    `orm:"column(tags);size(255);null" description:"标签"`
	Clicks            int64     `orm:"column(clicks)" description:"点击量"`
	Desc              string    `orm:"column(desc)" description:"简介-长"`
	Tip               string    `orm:"column(tip);size(50);null" description:"简介-简短"`
	Author            string    `orm:"column(author);size(30);null" description:"作者"`
	Copyright         string    `orm:"column(copyright);size(255);null" description:"版权"`
	Score             int8      `orm:"column(score)" description:"评分"`
	IsSign            int8      `orm:"column(is_sign)" description:"是否签约"`
	ReleaseTime       time.Time `orm:"column(release_time);type(datetime)" description:"释放时间"`
	CreateTime        time.Time `orm:"column(create_time);type(datetime)" description:"入库时间"`
	PublishStatus     int8      `orm:"column(publish_status)" description:"发布状态"`
	SerialId          string    `orm:"column(serial_id);size(32)" description:"序列编号"`
	ChannelType       int8      `orm:"column(channel_type)" description:"频道类型"`
	ChapterTime       time.Time `orm:"column(chapter_time);type(time)" description:"章节释放时间"`
	ChapterTotal      int       `orm:"column(chapter_total)" description:"章节总数"`
	ChapterDaily      int16     `orm:"column(chapter_daily)" description:"章节日更数量"`
	ChapterStart      int       `orm:"column(chapter_start)" description:"初始章节数量"`
	ChapterFinishTime time.Time `orm:"column(chapter_finish_time);type(datetime)" description:"章节动态完结时间"`
	ChapterPriceSum   int64     `orm:"column(chapter_price_sum)" description:"章节总价"`
	Price             int       `orm:"column(price);"`
}

type BookAndFirstChapter struct {
	Book
	FirstSerialId string
}

func (t *Book) TableName() string {
	return "book"
}

func init() {
	orm.RegisterModel(new(Book))
}

func GetBookByID(id int) *Book {
	o := orm.NewOrm()
	book := &Book{
		Id: id,
	}
	if err := o.Read(book); err != nil {
		fmt.Println("(GetBookByID)select book error.", err, id)
		return nil
	}
	return book
}

func GetBookByIdAndChannel(id int, channel int8) *BookAndFirstChapter {
	o := orm.NewOrm()
	if channel == 0 {
		book := &Book{
			Id: id,
		}
		if err := o.Read(book); err != nil {
			fmt.Println("(GetBookByIdAndChannel)select book error.", err, id)
			return nil
		}
		firstChapterSerial := ""
		o.Raw("select serial_id from book_chapter where book_id = ? and no = 1", id).QueryRow(&firstChapterSerial)
		return &BookAndFirstChapter{
			Book:          *book,
			FirstSerialId: firstChapterSerial,
		}
	} else {
		book := &Book{
			Id:          id,
			ChannelType: channel,
		}
		if err := o.Read(book, "id", "channel_type"); err != nil {
			fmt.Println("(GetBookByIdAndChannel)select book error.", err, id, channel)
			return nil
		}
		return &BookAndFirstChapter{
			Book: *book,
		}
	}
}

func UpdateBook(b *Book) bool {
	o := orm.NewOrm()
	if num, err := o.Update(b); err != nil || num == 0 {
		fmt.Println("update book fail.", err, num)
		return false
	}
	return true
}

func GetBookList(page, pageSize int, cond *orm.Condition) ([]map[string]string, int64, map[int]map[string]string) {
	o := orm.NewOrm()
	offset := (page - 1) * pageSize
	list := make([]*Book, 0)
	query := o.QueryTable(TableName("book"))
	query = query.SetCond(cond)
	total, _ := query.Count()
	query.OrderBy("id").Limit(pageSize, offset).All(&list)

	results := make([]map[string]string, 0)
	i := 1
	for _, v := range list {
		result := make(map[string]string)
		result["orderNum"] = strconv.Itoa(i)
		result["id"] = strconv.Itoa(v.Id)
		result["name"] = v.Name

		// 判断书籍类型  免费/VIP/收费
		bookType := ""
		for _, m := range configTopList {
			if m.BookId == v.Id {
				if m.TopicType == 4 {
					bookType = "VIP"
				}
			}
		}
		if v.ChapterPriceSum == 0 {
			if bookType != "VIP" {
				bookType = "免费"
			}
		} else {
			if bookType != "VIP" {
				bookType = "收费"
			}
		}
		result["bookType"] = bookType
		result["author"] = v.Author
		result["channelType"] = strconv.Itoa(int(v.ChannelType))

		// 判断书籍内容分类
		cat := ""
		for _, n := range catList {
			if v.Category == n.Id {
				cat = n.CategoryFullname
			}
		}
		result["cat"] = cat

		// 判断书籍标签
		tagArr := strings.Split(v.Tags, ",")
		tagNameArr := make([]string, 0)
		for i := 0; i < len(tagArr); i ++ {
			for _, t := range tagList {
				if tagArr[i] == strconv.Itoa(t.Id) {
					tagNameArr = append(tagNameArr, t.TagName)
				}
			}
		}
		result["tag"] = strings.Join(tagNameArr, ",")
		result["isSign"] = strconv.Itoa(int(v.IsSign))
		result["releaseTime"] = strings.Split(v.ReleaseTime.Format("2006-01-02 15:04:05"), " ")[0] + " " + v.ChapterTime.Format("15:04:05")

		// 判断书籍是否上架连载完结
		if compare := libs.CompareTime(v.ReleaseTime, time.Now()); compare >= 0 {
			result["status"] = "未上架"
		} else {
			if v.Status == 0 {
				result["status"] = "更新中"
			} else {
				if v.ReleaseChapterTotal() == v.ChapterTotal {
					result["status"] = "已完结"
				} else {
					result["status"] = "更新中"
				}
			}
		}

		result["words"] = strconv.Itoa(v.Words)
		result["clicks"] = strconv.FormatInt(v.Clicks, 10)
		result["totalChapter"] = strconv.Itoa(v.ChapterTotal)
		result["onlineChapter"] = strconv.Itoa(v.ReleaseChapterTotal())
		result["priceSum"] = strconv.Itoa(int(v.ChapterPriceSum))
		result["price"] = strconv.Itoa(int(v.Price))

		result["desc"] = v.Desc
		result["tip"] = v.Tip
		result["chapterPriceSum"] = strconv.Itoa(int(v.ChapterPriceSum))
		result["serialId"] = v.SerialId
		result["ossUrl"] = GetCatById(v.Category).OssPath
		results = append(results, result)
		i ++
	}

	tableHead := map[int]map[string]string{
		0:{"orderNum":      "序号"},
		1:{"id":            "小说Id"},
		2:{"name":          "书名"},
		3:{"bookType":      "类型"},
		4:{"author":        "作者名"},
		5:{"channelType":   "频道"},
		6:{"cat":           "分类"},
		7:{"tag":           "标签"},
		8:{"isSign":        "来源"},
		9:{"status":        "状态"},
		10:{"clicks":        "点击数"},
		11:{"releaseTime":   "上架时间"},
		12:{"words":         "总字数"},
		13:{"totalChapter":  "全部章节"},
		14:{"onlineChapter": "上线章节"},
		15:{"priceSum":      "总价"},
		16:{"price":         "单价"},
		17:{"desc":          "简介一"},
		18:{"tip":           "简介二"},
	}

	return results, total, tableHead
}

func GetTotal() map[string]int {
	totalList := make(map[string]int)
	o := orm.NewOrm()
	query := o.QueryTable(TableName("book"))
	total, _ := query.Count()
	totalList["totalNum"] = int(total)

	totalSign := 0
	o.Raw("select count(*) from book where is_sign = ?", 1).QueryRow(&totalSign)
	totalList["totalSign"] = totalSign
	totalList["totalUnSign"] = totalList["totalNum"] - totalSign

	maleNum := 0
	o.Raw("select count(*) from book where channel_type = ?", 1).QueryRow(&maleNum)
	totalList["maleNum"] = maleNum

	femaleNum := 0
	o.Raw("select count(*) from book where channel_type = ?", 2).QueryRow(&femaleNum)
	totalList["femaleNum"] = femaleNum

	return totalList
}

func UpdateClicks(id int, clicks int64) (int64, error) {
	o := orm.NewOrm()
	book := &Book{Id: id, Clicks: clicks}

	num, err := o.Update(book, "Clicks")
	if err != nil {
		return 0, err
		fmt.Println("update clicks error", err)
	}

	return num, nil
}

func (b *Book) ReleaseChapterTotal() int {
	if compare := libs.CompareTime(b.ReleaseTime, time.Now()); compare > 0 {
		return 0
	}
	if b.ChapterDaily > 0 && b.ChapterStart > 0 {
		now := time.Now()
		if compare := libs.CompareTime(b.ChapterFinishTime, now); compare <= 0 {
			return b.ChapterTotal
		}

		// 动态计算可发布章节数
		days := (now.Unix() - b.ChapterStartTime().Unix()) / 3600 / 24
		total := int(b.ChapterDaily)*int(days) + b.ChapterStart
		if total > b.ChapterTotal {
			total = b.ChapterTotal
		}
		return total
	}
	return b.ChapterTotal
}

func (b *Book) ChapterStartTime() time.Time {
	year, month, day := b.ReleaseTime.Date()
	hour, min, sec := b.ChapterTime.Clock()
	return time.Date(year, month, day, hour, min, sec, 0, time.Local)
}

func UpdateBookPriceById(bookId, price int) error {
	o := orm.NewOrm()
	_, err := o.Raw("update book set price = ? where id = ?", price, bookId).Exec()
	if err != nil {
		fmt.Println("update price from book error", err)
		return err
	}
	return nil
}
